﻿using CSRedis;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ongoal.Quotation.Redis
{
    /// <summary>
    /// 
    /// </summary>
    public class RedisProvider : IRedisProvider
    {
        private Dictionary<string, CSRedisClient> _Clients;
        public RedisProvider(List<RedisConfig> Cfgs)
        {
            _Clients = new Dictionary<string, CSRedisClient>();
            if (Cfgs == null || Cfgs.Count == 0)
                return;
            foreach (var item in Cfgs)
            {
                if (string.IsNullOrEmpty(item.Name) || string.IsNullOrEmpty(item.Connectstr))
                    continue;
                if (_Clients.ContainsKey(item.Name))
                    throw new System.Exception("redis 配置了重复的名称");
                _Clients.Add(item.Name, new CSRedisClient(item.Connectstr));
            }
        }
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public T Get<T>(string key, string name = "")
        {
            return GetClient(name).Get<T>(key);
        }
        //
        // 摘要:
        //     获取指定 key 的值
        //
        // 参数:
        //   key:
        //     不含prefix前辍
        public string Get(string key, string name = "")
        {
            return GetClient(name).Get(key);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public Task<T> GetAsync<T>(string key, string name = "")
        {
            return GetClient(name).GetAsync<T>(key);
        }

        public Task<string> GetAsync(string key, string name = "")
        {
            return GetClient(name).GetAsync(key);
        }
        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">Key</param>
        /// <param name="value">值</param>
        /// <param name="expireSeconds">过期时间</param>
        /// <param name="name">名称</param>
        /// <returns></returns>
        public bool Set(string key, object value, int expireSeconds = -1, string name = "")
        {
            return GetClient(name).Set(key, value, expireSeconds);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expireSeconds"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public Task<bool> SetAsync(string key, object value, int expireSeconds = -1, string name = "")
        {
            return GetClient(name).SetAsync(key, value, expireSeconds);
        }

        public CSRedisClient GetClient(string name)
        {
            CSRedisClient client = null;
            if (!string.IsNullOrEmpty(name))
            {
                if (!_Clients.ContainsKey(name))
                    throw new System.Exception($"找不到名称为{name}的redis配置");
                client = _Clients[name];
            }
            else
            {
                var tempkpai = _Clients.FirstOrDefault();
                client = tempkpai.Value;
            }
            if (client == null)
                throw new System.Exception("获取配置失败");            
            return client;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool Exists(string key, string name = "")
        {
            return GetClient(name).Exists(key);
        }

        public Task<bool> ExistsAsync(string key, string name = "")
        {
            return GetClient(name).ExistsAsync(key);
        }

        public bool Expire(string key, int seconds, string name = "")
        {
            return GetClient(name).Expire(key, seconds);
        }

        public bool Expire(string key, TimeSpan expire, string name = "")
        {
            return GetClient(name).Expire(key, expire);
        }

        public Task<bool> ExpireAsync(string key, int seconds, string name = "")
        {
            return GetClient(name).ExpireAsync(key, seconds);
        }

        public Task<bool> ExpireAsync(string key, TimeSpan expire, string name = "")
        {
            return GetClient(name).ExpireAsync(key, expire);
        }

        public bool ExpireAt(string key, DateTime expire, string name = "")
        {
            return GetClient(name).ExpireAt(key, expire);
        }

        public Task<bool> ExpireAtAsync(string key, DateTime expire, string name = "")
        {
            return GetClient(name).ExpireAtAsync(key, expire);
        }

        public T CacheShell<T>(string key, string field, int timeoutSeconds, SqlSugarClient db, Func<SqlSugarClient, T> getData, string name = "")
        {
            return GetClient(name).CacheShell<T>(key, field, timeoutSeconds, () => getData(db));
        }

        public T CacheShell<T>(string key, int timeoutSeconds, SqlSugarClient db, Func<SqlSugarClient, T> getData, string name = "")
        {
            return GetClient(name).CacheShell<T>(key, timeoutSeconds, () => getData(db));
        }

        public Task<T> CacheShellAsync<T>(string key, string field, int timeoutSeconds, SqlSugarClient db, Func<SqlSugarClient, Task<T>> getDataAsync, string name = "")
        {
            return GetClient(name).CacheShellAsync<T>(key, field, timeoutSeconds, () => getDataAsync(db));
        }

        public Task<T> CacheShellAsync<T>(string key, int timeoutSeconds, SqlSugarClient db, Func<SqlSugarClient, Task<T>> getDataAsync, string name = "")
        {
            return GetClient(name).CacheShellAsync<T>(key, timeoutSeconds, () => getDataAsync(db));
        }

        public long Del(string name = "", params string[] key)
        {
            return GetClient(name).Del(key);
        }

        public Task<long> DelAsync(string name = "", params string[] key)
        {
            return GetClient(name).DelAsync(key);
        }
        /// <summary>
        /// 分布式锁
        /// </summary>
        /// <param name="lockTimeout">锁时间 单位毫秒</param>
        /// <param name="lockkey">锁键</param>
        /// <param name="GetLockAction">获取锁方法</param>
        /// <param name="MissLockAction">未获取锁方法</param>
        /// <param name="name">reids客户端名称</param>
        public void DistributedLock(long lockTimeout, string lockkey, Action GetLockAction, Action MissLockAction, string name = "")
        {
            DistributedLock(lockTimeout, lockkey, (obj) => { GetLockAction?.Invoke(); }, (obj) => { MissLockAction?.Invoke(); }, name, null);
        }
        /// <summary>
        /// 分布式锁
        /// </summary>
        /// <param name="lockTimeout">锁时间 单位毫秒</param>
        /// <param name="lockkey">锁键</param>
        /// <param name="GetLockAction">获取锁方法</param>
        /// <param name="MissLockAction">未获取锁方法</param>
        /// <param name="name">reids客户端名称</param>
        /// <param name="actionparams">传入参数</param>
        public void DistributedLock(long lockTimeout, string lockkey, Action<object[]> GetLockAction, Action<object[]> MissLockAction, string name = "", params object[] actionparams)
        {
            var redisClient = GetClient(name);
            var currentTime = DateTime.Now.ToUnixTime();

            if (SetNxV2(redisClient, lockkey, DateTime.Now.ToUnixTime() + lockTimeout))
            {
                //设置过期时间
                redisClient.Expire(lockkey, TimeSpan.FromMilliseconds(lockTimeout));
                //TODO:一些业务逻辑代码
                try
                {
                    GetLockAction?.Invoke(actionparams);
                }
                catch (Exception err)
                {

                    throw err;
                }
                finally
                {
                    //最后释放锁
                    Remove(redisClient, lockkey);
                }
            }
            else
            {
                //未获取到锁，继续判断，判断时间戳看看是否可以重置并获取锁
                var lockValue = redisClient.Get(lockkey);
                var time = DateTime.Now.ToUnixTime();

                if (!string.IsNullOrEmpty(lockValue) && time > Convert.ToInt64(lockValue))
                {
                    //再次用当前时间戳getset
                    //返回固定key的旧值，旧值判断是否可以获取锁
                    var getsetResult = redisClient.GetSet(lockkey, time);
                    if (getsetResult == null || (getsetResult != null && getsetResult == lockValue))
                    {
                        Console.WriteLine("获取到Redis锁了");
                        //真正获取到锁
                        redisClient.Expire(lockkey, TimeSpan.FromMilliseconds(lockTimeout));
                        //TODO:一些业务逻辑代码
                        try
                        {
                            GetLockAction?.Invoke(actionparams);
                        }
                        catch (Exception err)
                        {

                            throw err;
                        }
                        finally
                        {
                            Console.WriteLine("处理业务");
                            //最后释放锁
                            Remove(redisClient, lockkey);
                        }

                    }
                    else
                    {
                        MissLockAction?.Invoke(actionparams);
                        Console.WriteLine("没有获取到锁");
                    }

                }
                else
                {
                    MissLockAction?.Invoke(actionparams);
                    Console.WriteLine("没有获取到锁");
                }
            }
        }
        /// <summary>
        /// 带返回的分布式锁
        /// </summary>
        /// <param name="lockTimeout">锁时间 单位毫秒</param>
        /// <param name="lockkey">锁键</param>
        /// <param name="GetLockFunc">获取锁方法</param>
        /// <param name="MissLockFunc">未获取锁方法</param>
        /// <param name="name">reids客户端名称</param>
        /// <returns></returns>
        public object DistributedLock(int lockTimeout, string lockkey, Func<object> GetLockFunc, Func<object> MissLockFunc, string name = "")
        {
            return DistributedLock(lockTimeout, lockkey, (obj) => { return GetLockFunc?.Invoke(); }, (obj) => { return MissLockFunc?.Invoke(); }, name, null);
        }
        /// <summary>
        /// 有返回带参数的分布式锁
        /// </summary>
        /// <param name="lockTimeout">锁时间 单位毫秒</param>
        /// <param name="lockkey">锁键</param>
        /// <param name="GetLockFunc">获取锁方法</param>
        /// <param name="MissLockFunc">未获取锁方法</param>
        /// <param name="name">reids客户端名称</param>
        /// <param name="funcParams">传入参数</param>
        /// <returns></returns>
        public object DistributedLock(int lockTimeout, string lockkey, Func<object[], object> GetLockFunc, Func<object[], object> MissLockFunc, string name = "", params object[] funcParams)
        {
            var redisClient = GetClient(name);
            var currentTime = DateTime.Now.ToUnixTime();
            object result = null;
            if (SetNxV2(redisClient, lockkey, DateTime.Now.ToUnixTime() + lockTimeout))
            {
                //设置过期时间
                redisClient.Expire(lockkey, TimeSpan.FromMilliseconds(lockTimeout));
                //TODO:一些业务逻辑代码
                try
                {
                    result = GetLockFunc?.Invoke(funcParams);
                }
                catch (Exception err)
                {

                    throw err;
                }
                finally
                {  //最后释放锁
                    Remove(redisClient, lockkey);
                }


            }
            else
            {
                //未获取到锁，继续判断，判断时间戳看看是否可以重置并获取锁
                var lockValue = redisClient.Get(lockkey);
                var time = DateTime.Now.ToUnixTime();

                if (!string.IsNullOrEmpty(lockValue) && time > Convert.ToInt64(lockValue))
                {
                    //再次用当前时间戳getset
                    //返回固定key的旧值，旧值判断是否可以获取锁
                    var getsetResult = redisClient.GetSet(lockkey, time);
                    if (getsetResult == null || (getsetResult != null && getsetResult == lockValue))
                    {
                        Console.WriteLine("获取到Redis锁了");
                        //真正获取到锁
                        redisClient.Expire(lockkey, TimeSpan.FromMilliseconds(lockTimeout));
                        //TODO:一些业务逻辑代码
                        try
                        {
                            result = GetLockFunc?.Invoke(funcParams);
                            Console.WriteLine("处理业务");
                        }
                        catch (Exception err)
                        {

                            throw err;
                        }
                        finally
                        {
                            //最后释放锁
                            Remove(redisClient, lockkey);
                        }
                    }
                    else
                    {
                        result = MissLockFunc?.Invoke(funcParams);
                        Console.WriteLine("没有获取到锁");
                    }

                }
                else
                {
                    result = MissLockFunc?.Invoke(funcParams);
                    Console.WriteLine("没有获取到锁");
                }
            }
            return result;
        }
        private bool SetNxV2(CSRedisClient redisClient, string key, long time)
        {
            if (redisClient.SetNx(key, time))
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 删除键
        /// </summary>
        /// <param name="redisClient"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        private bool Remove(CSRedisClient redisClient, string key)
        {
            return redisClient.Del(key) > 0;
        }
        /// <summary>
        /// 获取多个指定 key 的值(数组)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="keys">键值数组</param>
        /// <param name="name">Redis配置名称</param>
        /// <returns></returns>
        public T[] MGet<T>(string name = "", params string[] keys)
        {
            return GetClient(name).MGet<T>(keys);
        }
        /// <summary>
        /// 获取多个指定 key 的值(数组)
        /// </summary>
        /// <param name="name">键值数组</param>
        /// <param name="keys">Redis配置名称</param>
        /// <returns></returns>
        public string[] MGet(string name = "", params string[] keys)
        {
            return GetClient(name).MGet(keys);
        }
        /// <summary>
        /// 获取多个指定 key 的值(数组)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name">Redis配置名称</param>
        /// <param name="keys">键值数组</param>
        /// <returns></returns>
        public Task<T[]> MGetAsync<T>(string name = "", params string[] keys)
        {
            return GetClient(name).MGetAsync<T>(keys);
        }
        /// <summary>
        /// 获取多个指定 key 的值(数组)
        /// </summary>
        /// <param name="name">Redis配置名称</param>
        /// <param name="keys">键值数组</param>
        /// <returns></returns>
        public Task<string[]> MGetAsync(string name = "", params string[] keys)
        {
            return GetClient(name).MGetAsync(keys);
        }
        /// <summary>
        /// 同时设置一个或多个 key-value 对
        /// </summary>
        /// <param name="name"></param>
        /// <param name="keyValues"></param>
        /// <returns></returns>
        public bool MSet(string name = "", params object[] keyValues)
        {
            return GetClient(name).MSet(keyValues);
        }
        /// <summary>
        /// 同时设置一个或多个 key-value 对
        /// </summary>
        /// <param name="name"></param>
        /// <param name="keyValues"></param>
        /// <returns></returns>
        public Task<bool> MSetAsync(string name = "", params object[] keyValues)
        {
            return GetClient(name).MSetAsync(keyValues);
        }
        /// <summary>
        /// 同时设置一个或多个 key-value 对，当且仅当所有给定 key 都不存在
        /// </summary>
        /// <param name="name"></param>
        /// <param name="keyValues"></param>
        /// <returns></returns>
        public bool MSetNx(string name = "", params object[] keyValues)
        {
            return GetClient(name).MSetNx(keyValues);
        }
        /// <summary>
        /// 同时设置一个或多个 key-value 对，当且仅当所有给定 key 都不存在
        /// </summary>
        /// <param name="name"></param>
        /// <param name="keyValues"></param>
        /// <returns></returns>
        public Task<bool> MSetNxAsync(string name = "", params object[] keyValues)
        {
            return GetClient(name).MSetNxAsync(keyValues);
        }
        /// <summary>
        /// 有在 key 不存在时设置 key 的值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="name">Redis配置名称</param>
        /// <returns></returns>
        public bool SetNx(string key, object value, string name = "")
        {
            return GetClient(name).SetNx(key, value);
        }
        /// <summary>
        /// 有在 key 不存在时设置 key 的值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="name">Redis配置名称</param>
        /// <returns></returns>
        public Task<bool> SetNxAsync(string key, object value, string name = "")
        {
            return GetClient(name).SetNxAsync(key, value);
        }
        /// <summary>
        /// 创建管道传输，注意：官方集群时请务必预热slotCache，否则会产生moved错误
        /// </summary>
        /// <param name="handler"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public object[] StartPipe(Action<CSRedisClientPipe<string>> handler, string name = "")
        {
            return GetClient(name).StartPipe(handler);
        }
        /// <summary>
        /// 创建管道传输，注意：官方集群时请务必预热slotCache，否则会产生moved错误，打包提交如：RedisHelper.StartPipe().Set("a",  "1").HSet("b", "f", "2").EndPipe();
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public CSRedisClientPipe<string> StartPipe(string name = "")
        {
            return GetClient(name).StartPipe();
        }
        /// <summary>
        /// 将一个或多个值插入到列表头部 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <param name="key">Key键</param>
        /// <param name="value"></param>
        /// <returns></returns>
        public long LPush<T>(string key, string name = "", params T[] value)
        {
            return GetClient(name).LPush<T>(key, value);
        }
        /// <summary>
        /// 将一个或多个值插入到列表头部 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <param name="key">Key键</param>
        /// <param name="value"></param>
        /// <returns></returns>
        public Task<long> LPushAsync<T>(string key, string name = "", params T[] value)
        {
            return GetClient(name).LPushAsync<T>(key, value);
        }

        public T RPop<T>(string key, string name = "")
        {
            return GetClient(name).RPop<T>(key);
        }

        public string RPop(string key, string name = "")
        {
            return GetClient(name).RPop(key);
        }

        public Task<T> RPopAsync<T>(string key, string name = "")
        {
            return GetClient(name).RPopAsync<T>(key);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public Task<string> RPopAsync(string key, string name = "")
        {
            return GetClient(name).RPopAsync(key);
        }
        /// <summary>
        /// 将哈希表 key 中的字段 field 的值设为 value
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="field">字段</param>
        /// <param name="value">值</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public bool HSet(string key, string field, object value, string name = "")
        {
            return GetClient(name).HSet(key, field, value);
        }
        /// <summary>
        /// 将哈希表 key 中的字段 field 的值设为 value
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="field">字段</param>
        /// <param name="value">值</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public Task<bool> HSetAsync(string key, string field, object value, string name = "")
        {
            return GetClient(name).HSetAsync(key, field, value);
        }
        /// <summary>
        /// 获取存储在哈希表中指定字段的值
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="key">键</param>
        /// <param name="field">字段</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public T HGet<T>(string key, string field, string name = "")
        {
            return GetClient(name).HGet<T>(key, field);
        }
        /// <summary>
        /// 获取存储在哈希表中指定字段的值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="field">字段</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public string HGet(string key, string field, string name = "")
        {
            return GetClient(name).HGet(key, field);
        }
        /// <summary>
        /// 获取存储在哈希表中指定字段的值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public Task<string> HGetAsync(string key, string field, string name = "")
        {
            return GetClient(name).HGetAsync(key, field);
        }
        /// <summary>
        /// 获取存储在哈希表中指定字段的值
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="key">键</param>
        /// <param name="field">字段</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public Task<T> HGetAsync<T>(string key, string field, string name = "")
        {
            return GetClient(name).HGetAsync<T>(key, field);
        }
        /// <summary>
        /// 获取在哈希表中指定 key 的所有字段和值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public Dictionary<string, string> HGetAll(string key, string name = "")
        {
            return GetClient(name).HGetAll(key);
        }
        /// <summary>
        /// 获取在哈希表中指定 key 的所有字段和值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public Dictionary<string, T> HGetAll<T>(string key, string name = "")
        {
            return GetClient(name).HGetAll<T>(key);
        }
        /// <summary>
        /// 获取在哈希表中指定 key 的所有字段和值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public Task<Dictionary<string, string>> HGetAllAsync(string key, string name = "")
        {
            return GetClient(name).HGetAllAsync(key);
        }
        /// <summary>
        /// 获取在哈希表中指定 key 的所有字段和值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public Task<Dictionary<string, T>> HGetAllAsync<T>(string key, string name = "")
        {
            return GetClient(name).HGetAllAsync<T>(key);
        }
        /// <summary>
        /// 删除一个或多个哈希表字段
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <param name="fields"></param>
        /// <returns></returns>
        public long HDel(string key, string name = "", params string[] fields)
        {
            return GetClient(name).HDel(key, fields);
        }
        /// <summary>
        /// 删除一个或多个哈希表字段
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <param name="fields"></param>
        /// <returns></returns>
        public Task<long> HDelAsync(string key, string name = "", params string[] fields)
        {
            return GetClient(name).HDelAsync(key, fields);
        }
        /// <summary>
        /// 查看哈希表 key 中，指定的字段是否存在
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="field">字段</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public bool HExists(string key, string field, string name = "")
        {
            return GetClient(name).HExists(key, field);
        }
        /// <summary>
        /// 查看哈希表 key 中，指定的字段是否存在
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="field">字段</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public Task<bool> HExistsAsync(string key, string field, string name = "")
        {
            return GetClient(name).HExistsAsync(key, field);
        }
        /// <summary>
        /// 向集合添加一个或多个成员
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <param name="members">一个或多个成员</param>
        /// <returns></returns>
        public long SAdd<T>(string key, string name = "", params T[] members)
        {
            return GetClient(name).SAdd<T>(key, members);
        }
        /// <summary>
        /// 向集合添加一个或多个成员
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <param name="members">一个或多个成员</param>
        /// <returns></returns>
        public Task<long> SAddAsync<T>(string key, string name = "", params T[] members)
        {
            return GetClient(name).SAddAsync<T>(key, members);
        }
        /// <summary>
        /// 获取所有哈希表中的字段
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public string[] HKeys(string key, string name = "")
        {
            return GetClient(name).HKeys(key);
        }
        /// <summary>
        /// 获取所有哈希表中的字段
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public Task<string[]> HKeysAsync(string key, string name = "")
        {
            return GetClient(name).HKeysAsync(key);
        }
        /// <summary>
        /// 获取哈希表中字段的数量
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public long HLen(string key, string name = "")
        {
            return GetClient(name).HLen(key);
        }
        /// <summary>
        /// 获取哈希表中字段的数量
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <returns></returns>
        public Task<long> HLenAsync(string key, string name = "")
        {
            return GetClient(name).HLenAsync(key);
        }
        /// <summary>
        /// 获取存储在哈希表中多个字段的值
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <param name="fields">字段</param>
        /// <returns></returns>
        public string[] HMGet(string key, string name = "", params string[] fields)
        {
            return GetClient(name).HMGet(key, fields);
        }
        /// <summary>
        /// 获取存储在哈希表中多个字段的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <param name="fields">字段</param>
        /// <returns></returns>
        public T[] HMGet<T>(string key, string name = "", params string[] fields)
        {
            return GetClient(name).HMGet<T>(key, fields);
        }
        /// <summary>
        /// 同时将多个 field-value (域-值)对设置到哈希表 key 中
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <param name="keyValues"> key1 value1 [key2 value2]</param>
        /// <returns></returns>
        public bool HMSet(string key, string name = "", params object[] keyValues)
        {
            return GetClient(name).HMSet(key, keyValues);
        }
        /// <summary>
        /// 同时将多个 field-value (域-值)对设置到哈希表 key 中
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">配置名称</param>
        /// <param name="keyValues"> key1 value1 [key2 value2]</param>
        /// <returns></returns>
        public Task<bool> HMSetAsync(string key, string name = "", params object[] keyValues)
        {
            return GetClient(name).HMSetAsync(key, keyValues);
        }
        /// <summary>
        /// 返回集合中的所有成员
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">键</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public T[] SMembers<T>(string key, string name = "")
        {
            return GetClient(name).SMembers<T>(key);
        }
        /// <summary>
        /// 返回集合中的所有成员
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public string[] SMembers(string key, string name = "")
        {
            return GetClient(name).SMembers(key);
        }
        /// <summary>
        /// 返回集合中的所有成员
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public Task<string[]> SMembersAsync(string key, string name = "")
        {
            return GetClient(name).SMembersAsync(key);
        }
        /// <summary>
        /// 返回集合中的所有成员
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public Task<T[]> SMembersAsync<T>(string key, string name = "")
        {
            return GetClient(name).SMembersAsync<T>(key);
        }
        /// <summary>
        /// 移除集合中一个或多个成员
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="key">键</</param>
        /// <param name="members">一个或多个成员</param>
        /// <returns></returns>
        public long SRem<T>(string name, string key, params T[] members)
        {
            return GetClient(name).SRem<T>(key, members);
        }
        /// <summary>
        /// 移除集合中一个或多个成员
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="key">键</param>
        /// <param name="members">一个或多个成员</param>
        /// <returns></returns>
        public Task<long> SRemAsync<T>(string name, string key, params T[] members)
        {
            return GetClient(name).SRemAsync<T>(key, members);
        }
        /// <summary>
        ///  判断 member 元素是否是集合 key 的成员
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="member">成员</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public bool SIsMember(string key, object member, string name = "")
        {
            return GetClient(name).SIsMember(key, member);
        }
        /// <summary>
        ///  判断 member 元素是否是集合 key 的成员
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="member">成员</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public Task<bool> SIsMemberAsync(string key, object member, string name = "")
        {
            return GetClient(name).SIsMemberAsync(key, member);
        }
        /// <summary>
        /// 返回给定所有集合的差集
        /// </summary>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="keys">键集合</param>
        /// <returns></returns>
        public string[] SDiff(string name, params string[] keys)
        {
            return GetClient(name).SDiff(keys);
        }
        /// <summary>
        /// 返回给定所有集合的差集
        /// </summary>
        /// <typeparam name="T"> byte[] 或其他类型</typeparam>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="keys">键集合</param>
        /// <returns></returns>
        public T[] SDiff<T>(string name, params string[] keys)
        {
            return GetClient(name).SDiff<T>(keys);
        }
        /// <summary>
        /// 返回给定所有集合的差集
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="keys">键集合</param>
        /// <returns></returns>
        public Task<T[]> SDiffAsync<T>(string name, params string[] keys)
        {
            return GetClient(name).SDiffAsync<T>(keys);
        }
        /// <summary>
        /// 返回给定所有集合的差集
        /// </summary>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="keys">键集合</param>
        /// <returns></returns>
        public Task<string[]> SDiffAsync(string name, params string[] keys)
        {
            return GetClient(name).SDiffAsync(keys);
        }
        /// <summary>
        /// 返回给定所有集合的交集
        /// </summary>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="keys">键集合</param>
        /// <returns></returns>
        public string[] SInter(string name, params string[] keys)
        {
            return GetClient(name).SInter(keys);
        }
        /// <summary>
        /// 返回给定所有集合的交集
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="keys">键集合</param>
        /// <returns></returns>
        public T[] SInter<T>(string name, params string[] keys)
        {
            return GetClient(name).SInter<T>(keys);
        }
        /// <summary>
        /// 返回给定所有集合的交集
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="keys">键集合</param>
        /// <returns></returns>
        public Task<T[]> SInterAsync<T>(string name, params string[] keys)
        {
            return GetClient(name).SInterAsync<T>(keys);
        }
        /// <summary>
        /// 返回给定所有集合的交集
        /// </summary>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="keys">键集合</param>
        /// <returns></returns>
        public Task<string[]> SInterAsync(string name, params string[] keys)
        {
            return GetClient(name).SInterAsync(keys);
        }
        /// <summary>
        /// 返回所有给定集合的并集
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="keys">键集合</param>
        /// <returns></returns>
        public T[] SUnion<T>(string name, params string[] keys)
        {
            return GetClient(name).SUnion<T>(keys);
        }
        /// <summary>
        /// 返回所有给定集合的并集
        /// </summary>
        /// <param name="keys">键集合</param>
        /// <returns></returns>
        public string[] SUnion(string name, params string[] keys)
        {
            return GetClient(name).SUnion(keys);
        }
        /// <summary>
        /// 返回所有给定集合的并集
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="keys">键集合</param>
        /// <returns></returns>
        public Task<T[]> SUnionAsync<T>(string name, params string[] keys)
        {
            return GetClient(name).SUnionAsync<T>(keys);
        }

        public Task<string[]> SUnionAsync(string name, params string[] keys)
        {
            return GetClient(name).SUnionAsync(keys);
        }
        /// <summary>
        /// 向有序集合添加一个或多个成员，或者更新已存在成员的分数
        /// </summary>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="key">键</param>
        /// <param name="scoreMembers">一个或多个成员分数</param>
        /// <returns></returns>
        public long ZAdd(string name, string key, params (decimal, object)[] scoreMembers)
        {
            return GetClient(name).ZAdd(key, scoreMembers);
        }
        /// <summary>
        ///  向有序集合添加一个或多个成员，或者更新已存在成员的分数
        /// </summary>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="key">键</param>
        /// <param name="scoreMembers">一个或多个成员分数</param>
        /// <returns></returns>
        public Task<long> ZAddAsync(string name, string key, params (decimal, object)[] scoreMembers)
        {
            return GetClient(name).ZAddAsync(key, scoreMembers);
        }
        /// <summary>
        /// 获取有序集合的成员数量
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public long ZCard(string key, string name = "")
        {
            return GetClient(name).ZCard(key);
        }
        /// <summary>
        /// 获取有序集合的成员数量
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public Task<long> ZCardAsync(string key, string name = "")
        {
            return GetClient(name).ZCardAsync(key);
        }
        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="min">分数最小值 double.MinValue 1</param>
        /// <param name="max">分数最大值 double.MaxValue 10</param>
        /// <param name="count">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public string[] ZRangeByScore(string key, decimal min, decimal max, long? count = null, long offset = 0, string name = "")
        {
            return GetClient(name).ZRangeByScore(key, min, max, count, offset);
        }
        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key"></param>
        /// <param name="min">分数最小值 double.MinValue 1</param>
        /// <param name="max">分数最大值 double.MaxValue 10</param>
        /// <param name="count">返回多少成员</param>
        /// <param name="offset"> byte[] 或其他类型</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public T[] ZRangeByScore<T>(string key, decimal min, decimal max, long? count = null, long offset = 0, string name = "")
        {
            return GetClient(name).ZRangeByScore<T>(key, min, max, count, offset);
        }
        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min"> 分数最小值 -inf (1 1</param>
        /// <param name="max">分数最大值 +inf (10 10</param>
        /// <param name="count">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public string[] ZRangeByScore(string key, string min, string max, long? count = null, long offset = 0, string name = "")
        {
            return GetClient(name).ZRangeByScore(key, min, max, count, offset);
        }
        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 -inf (1 1</param>
        /// <param name="max">分数最大值 +inf (10 10</param>
        /// <param name="count"> 返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public T[] ZRangeByScore<T>(string key, string min, string max, long? count = null, long offset = 0, string name = "")
        {
            return GetClient(name).ZRangeByScore<T>(key, min, max, count, offset);
        }
        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员
        /// </summary>
        /// <param name="key">不含prefix前辍</param>
        /// <param name="min">分数最小值 double.MinValue 1</param>
        /// <param name="max">分数最大值 double.MaxValue 10</param>
        /// <param name="count">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public Task<string[]> ZRangeByScoreAsync(string key, decimal min, decimal max, long? count = null, long offset = 0, string name = "")
        {
            return GetClient(name).ZRangeByScoreAsync(key, min, max, count, offset);
        }
        /// <summary>
        /// 通过分数返回有序集合指定区间内的成员
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key">键</param>
        /// <param name="min"> 分数最小值 double.MinValue 1</param>
        /// <param name="max">分数最大值 double.MaxValue 10</param>
        /// <param name="count">返回多少成员</param>
        /// <param name="offset">返回条件偏移位置</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public Task<T[]> ZRangeByScoreAsync<T>(string key, decimal min, decimal max, long? count = null, long offset = 0, string name = "")
        {
            return GetClient(name).ZRangeByScoreAsync<T>(key, min, max, count, offset);
        }
        /// <summary>
        /// 通过索引区间返回有序集合成指定区间内的成员和分数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop"> 结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public (T member, decimal score)[] ZRangeWithScores<T>(string key, long start, long stop, string name = "")
        {
            return GetClient(name).ZRangeWithScores<T>(key, start, stop);
        }
        /// <summary>
        /// 通过索引区间返回有序集合成指定区间内的成员和分数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">键</param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop"> 结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public (string member, decimal score)[] ZRangeWithScores(string key, long start, long stop, string name = "")
        {
            return GetClient(name).ZRangeWithScores(key, start, stop);
        }
        /// <summary>
        /// 通过索引区间返回有序集合成指定区间内的成员和分数
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="key"></param>
        /// <param name="start">开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public Task<(T member, decimal score)[]> ZRangeWithScoresAsync<T>(string key, long start, long stop, string name = "")
        {
            return GetClient(name).ZRangeWithScoresAsync<T>(key, start, stop);
        }
        /// <summary>
        /// 通过索引区间返回有序集合成指定区间内的成员和分数
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="start"> 开始位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="stop">结束位置，0表示第一个元素，-1表示最后一个元素</param>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <returns></returns>
        public Task<(string member, decimal score)[]> ZRangeWithScoresAsync(string key, long start, long stop, string name = "")
        {
            return GetClient(name).ZRangeWithScoresAsync(key, start, stop);
        }
        /// <summary>
        /// 移除有序集合中的一个或多个成员
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="key">键</param>
        /// <param name="member">一个或多个成员</param>
        /// <returns></returns>
        public long ZRem<T>(string name, string key, params T[] member)
        {
            return GetClient(name).ZRem(key, member);
        }
        /// <summary>
        /// 移除有序集合中的一个或多个成员
        /// </summary>
        /// <typeparam name="T">byte[] 或其他类型</typeparam>
        /// <param name="name">客户端配置名称，为空为默认缓存</param>
        /// <param name="key">键</param>
        /// <param name="member">一个或多个成员</param>
        /// <returns></returns>
        public Task<long> ZRemAsync<T>(string name, string key, params T[] member)
        {
            return GetClient(name).ZRemAsync(key, member);
        }
        /// <summary>
        /// 保存主从关系型缓存
        /// </summary>
        /// <param name="miankey">主键</param>
        /// <param name="Detailkey">详细键</param>
        /// <param name="value">值</param>
        /// <param name="expireSeconds">过期时间</param>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool SetReliashObject(string miankey, string Detailkey, object value, int expireSeconds = -1, string name = "")
        {
            try
            {
                var clienttemp = GetClient(name);
                var pl = clienttemp.StartPipe();
                clienttemp.SAdd(miankey, Detailkey);
                clienttemp.Set(Detailkey, value, expireSeconds);
                pl.EndPipe();
                return true;
            }
            catch (Exception err)
            {

                return false;
            }

        }
        /// <summary>
        /// 删除主从关系型缓存
        /// </summary>
        /// <param name="Miankey">主表键-数据类型键</param>
        /// <param name="Detailkey">明细键</param>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool DetReliashObject(string Miankey, string Detailkey, string name = "")
        {
            try
            {
                var clienttemp = GetClient(name);
                var pl = clienttemp.StartPipe();
                clienttemp.SRem(Miankey, Detailkey);
                clienttemp.Del(Detailkey);
                pl.EndPipe();
                return true;
            }
            catch (Exception err)
            {

                return false;
            }
        }
        /// <summary>
        /// 获取所有主从关系型缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mainkey">主表键-数据类型键</param>
        /// <param name="name"></param>
        /// <returns></returns>
        public T[] GetReliashObjectAll<T>(string mainkey, string name = "")
        {
            try
            {
                var clienttemp = GetClient(name);
                var ids = clienttemp.SMembers(mainkey).ToArray();
                return clienttemp.MGet<T>(ids);
            }
            catch (Exception err)
            {

                return null;
            }
        }
        /// <summary>
        /// 分页获取主从关系型缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="mainkey"></param>
        /// <param name="pageindex"></param>
        /// <param name="PageSize"></param>
        /// <returns></returns>
        public T[] GetReliashObjectPage<T>(string mainkey, int pageindex, int PageSize, string name = "")
        {
            try
            {
                var clienttemp = GetClient(name);
                var ids = clienttemp.SMembers(mainkey).Take(PageSize).Skip((pageindex - 1) * PageSize).ToArray();
                return clienttemp.MGet<T>(ids);
            }
            catch (Exception err)
            {

                return null;
            }
        }
        /// <summary>
        /// 批量保存主从结构缓存缓存
        /// </summary>
        /// <param name="miankey"></param>
        /// <param name="values"></param>
        /// <param name="expireSeconds"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool SetReliashObject(string miankey, Dictionary<string, object> values, int expireSeconds = -1, string name = "")
        {
            try
            {
                var clienttemp = GetClient(name);
                var pl = clienttemp.StartPipe();
                foreach (var item in values)
                {
                    clienttemp.SAdd(miankey, item.Key);
                    clienttemp.Set(item.Key, item.Value, expireSeconds);
                }
                pl.EndPipe();
                return true;
            }
            catch (Exception err)
            {

                return false;
            }
        }
    }
}
